﻿using System.Linq;
using System.Threading;
using Citi.SecurityHelper;
using System.Threading.Tasks;
using SHDocVw;
using Citi.SecurityWebBrowser;
using EO.WebBrowser;
using System.Windows.Forms;
using EO.WebBrowser.WinForm;
using System;
using System.Diagnostics;

namespace EO.WebBrowser
{
    public static class SingleSignOnEO
    {
        private static string StartUrl;
        private static string SingleSignOnUrl;
        private static string Soeid;
        private static Citi.SecurityHelper.LoginType LoginType;
        private static WebView WebView;
        private static WebControl WebControl { get; set; }
        private static bool Logged;
        private static string AdditionalUrls;
        
        public static bool IsLogged(this WebView webBrowser)
        {
            return Logged;
        }

        static void webBrowser_LoadComplete(object sender, NavigationTaskEventArgs e)
        {
            LogUser(WebView);
        }

        public static void LogSingleSignOn(this WebControl webControl, string soeid, Citi.SecurityHelper.LoginType loginType, string startUrl = null, 
            string singleSignOnUrl = null, string additionalUrls = null)
        {
            StartUrl = StartUrl ?? startUrl;
            SingleSignOnUrl = singleSignOnUrl;
            Soeid = soeid;
            LoginType = loginType;
            WebControl = webControl;
            AdditionalUrls = additionalUrls;
            WebView = webControl.WebView;

            if (WebControl != null && WebControl.Parent != null)
            {
                webControl.Height = webControl.Parent.Height;
                WebView.TitleChanged += webBrowser_TitleChanged;
                WebControl.Parent.SizeChanged += EOBusinessObjectsExtraction_SizeChanged;
            }

            if (!string.IsNullOrWhiteSpace(startUrl))
                WebView.LoadUrl(startUrl);

            if (string.IsNullOrWhiteSpace(SingleSignOnUrl))
                WebView.LoadComplete += webBrowser_LoadComplete;
            else
                WebView.UrlChanged += WebView_UrlChanged ;

            var runningTime = DateTime.Now;
            while (Logged == false)
            {
                Application.DoEvents();
                Thread.Sleep(100);

                if ((DateTime.Now - runningTime).TotalSeconds > 90)
                    OpenAdditionalPages();
            }

            WebView.LoadComplete -= webBrowser_LoadComplete;
            WebView.LoadComplete -= LoggedLoadComplete;
        }

        static void WebView_UrlChanged(object sender, EventArgs e)
        {
            if (WebView.Url != SingleSignOnUrl) return;

            WebView.UrlChanged -= WebView_UrlChanged;
            
            LogUser(WebView);
            //WebView.LoadComplete += webBrowser_LoadComplete;
        }

        static void EOBusinessObjectsExtraction_SizeChanged(object sender, EventArgs e)
        {
            WebControl.Height = WebControl.Parent.Height;
        }

        static void webBrowser_TitleChanged(object sender, System.EventArgs e)
        {
            WebControl.Parent.Text = WebView.Title;
        }

        private static void LogUser(WebView webBrowser)
        {
            var password = CitiEncryption.GetDecryptedPassword(Soeid, LoginType, SecurityConfigurations.RobotUserName, SecurityConfigurations.RobotPassword);
            var document = webBrowser.GetDOMWindow().document;

            var textName = document.getElementsByName("USER");

            WaitUntilExist(webBrowser, "document.getElementsByName('USER')[0].value");

            //if (textName == null || !textName.Any()) return;

            webBrowser.EvalScript(string.Format("document.getElementsByName('USER')[0].value = '{0}';", Soeid));
            webBrowser.EvalScript(string.Format("document.getElementsByName('PASSWORD')[0].value = '{0}';", password));

            var inputs = document.getElementsByTagName("input").Cast<DOM.Element>();

            var button = inputs.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.outerHTML)
                && (x.outerHTML.ToLower().Contains("button") || x.outerHTML.ToLower().Contains("submit"))
                && (x.outerHTML.ToUpper().Contains("SIGN ON") || x.outerHTML.ToUpper().Contains("LOGIN") || x.outerHTML.ToUpper().Contains("LOG IN")));

            WebView.LoadComplete -= webBrowser_LoadComplete;

            try
            {
                button.InvokeFunction("onclick", null);
            }
            catch
            {
                button.InvokeFunction("click", null);
            }

            WebView.LoadComplete += LoggedLoadComplete;
        }

        static void LoggedLoadComplete(object sender, NavigationTaskEventArgs e)
        {
            OpenAdditionalPages();
        }

        private static void OpenAdditionalPages()
        {
            WebView.LoadComplete -= LoggedLoadComplete;

            if (string.IsNullOrWhiteSpace(AdditionalUrls))
            {
                Logged = true;
                return;
            }

            var urlsBo = AdditionalUrls.Split(new[] { "||" }, 20, StringSplitOptions.RemoveEmptyEntries).ToList();

            foreach (var url in urlsBo)
            {
                WebView.LoadUrl(url);

                var runningTime = DateTime.Now;

                while (Logged == false && (DateTime.Now - runningTime).TotalSeconds <= 20)
                {
                    Application.DoEvents();
                    Thread.Sleep(100);
                }
            }

            Logged = true;
        }

        public static bool AllElementExist(this WebView webView, string elementString)
        {
            var elements = elementString.Split('.');
            var javascriptExecuted = string.Empty;

            foreach (var element in elements)
            {
                if (!string.IsNullOrEmpty(javascriptExecuted))
                    javascriptExecuted += ".";

                javascriptExecuted += element;

                var exists = ElementExists(webView, javascriptExecuted);

                if (!exists) return false;
            }

            return true;
        }

        public static bool ElementExists(this WebView webView, string elementString)
        {
            return webView.CanEvalScript
                ? (bool)webView.EvalScript(string.Format("{0} != undefined", elementString))
                : false; ;
        }

        public static bool WaitUntilExist(this WebView webView, string elementString, int timeout = 60000, bool throwOnTimeout = true)
        {
            var elementsExist = webView.AllElementExist(elementString);
            var startDate = DateTime.Now;

            while (!elementsExist)
            {
                Application.DoEvents();
                Thread.Sleep(100);
                elementsExist = webView.AllElementExist(elementString);

                if ((DateTime.Now - startDate).TotalMilliseconds > timeout)
                {
                    if (throwOnTimeout)
                        throw new Exception(string.Format("Timeout expired. Could not find '{0}'", elementsExist));

                    return false;
                }
            }

            return true;
        }

        public static object EvaluateScript(this WebView webView, string javascript)
        {
            var ran = false;

            while (!ran)
            {
                if (!webView.CanEvalScript)
                    Thread.Sleep(50);

                try
                {
                    var objectEvaluated = webView.EvalScript(javascript);
                    ran = true;

                    return objectEvaluated;
                }
                catch { }
            }

            return null;
        }
    }
}
